# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File       : base_view.py
# Time       ：2023/3/12 13:10
# Author     ：Y-aong
# version    ：python 3.7
# Description：
    视图基类
    base views
"""
import traceback

from flask import request
from flask_restx import Resource, Api
from public.api_utils.api_decorator import handle_api_error
from .base_model import db
from .base_response import generate_response
from .logger import logger


class CustomApi(Api):

    def handle_error(self, e):
        if hasattr(e, 'description') and isinstance(getattr(e, 'description'), dict):
            return getattr(e, 'description')
        else:
            logger.error(f'服务器异常:{e}, \n异常详情:{traceback.format_exc()}')
            return super().handle_error(e)


base_api = CustomApi(
    title='ORDERLINES API接口文档',
    version='1.0.0.1',
    description='Keep the process organized',
    security="Bearer Auth",
    ordered=True,
    authorizations={
        "Bearer Auth": {
            "type": "apiKey",
            "in": "header",
            "name": "Authorization",
            "description": "Add a jwt with ** Bearer token"
        }
    },
    ui_config={
        'docExpansion': 'list',
        'operationsSorter': 'alpha',
        'tagsSorter': 'alpha'
    }
)


class AbstractView(Resource):
    def __init__(self, *args, **kwargs):
        super(AbstractView, self).__init__(*args, **kwargs)
        self.table_orm = None
        self.table_schema = None
        if request.method == 'GET':
            self.form_data: dict = request.args or {}
        elif request.method in ['POST', 'PUT']:
            self.form_data: dict = request.json or {}
        else:
            self.form_data = request.args or request.json
        self.filter = list()
        self.table_id = self.form_data.get('id')
        self.response_data = dict()
        self.pageNum = self.form_data.get('pageNum')
        self.pageSize = self.form_data.get('pageSize')
        # 日志记录配置
        self.is_logger = False
        self.get_action = None
        self.post_action = None
        self.put_action = None
        self.delete_action = None

    def handle_filter(self):
        for key, value in self.form_data.items():
            if hasattr(self.table_orm, key):
                self.filter.append(getattr(self.table_orm, key) == value)

    def handle_request_params(self):
        pass

    def handle_response_data(self):
        pass

    def response_callback(self):
        pass

    def _get_single(self):
        """单条查询, Single query"""
        single_data = db.session.query(self.table_orm).filter(*self.filter).first()
        if single_data:
            return self.table_schema().dump(single_data)
        return {}

    def _get_multi(self):
        """多条查询, Multiple query"""
        with db.auto_commit():
            multi_data = db.session.query(self.table_orm).filter(*self.filter).order_by(self.table_orm.id.desc())
            if self.pageNum and self.pageSize:
                multi_data = multi_data.paginate(page=int(self.pageNum), per_page=int(self.pageSize))
                items = self.table_schema().dump(multi_data.items, many=True)
                total = multi_data.total
                return {'list': items, 'total': total, 'pageNum': int(self.pageNum), 'pageSize': int(self.pageSize)}
            else:
                return self.table_schema().dump(multi_data, many=True)

    def check_form_data(self) -> bool:
        for key, val in self.form_data.items():
            if hasattr(self.table_orm, key):
                return False
        return True


class BaseDetailsView(AbstractView):
    def __init__(self, *args, **kwargs):
        super(BaseDetailsView, self).__init__(*args, **kwargs)

    @handle_api_error()
    def get(self):
        if self.table_orm:
            self.filter.append(self.table_orm.active == 1)
        self.response_data = self._get_single()
        self.handle_response_data()
        self.response_callback()
        return generate_response(self.response_data, message='select detail success')


class BaseView(AbstractView):
    def __init__(self, *args, **kwargs):
        super(BaseView, self).__init__(*args, **kwargs)

    @handle_api_error()
    def get(self):
        if self.table_orm:
            self.filter.append(self.table_orm.active == 1)
        self.handle_filter()
        self.response_data = self._get_multi()
        self.handle_response_data()
        self.response_callback()
        return generate_response(self.response_data, message='select list success')

    @handle_api_error()
    def post(self):
        self.handle_request_params()
        form_data = dict()
        for key, value in self.form_data.items():
            if hasattr(self.table_orm, key):
                form_data.setdefault(key, value)
        task = self.table_schema().load(form_data)
        with db.auto_commit():
            obj = self.table_orm(**task)
            db.session.add(obj)
        self.response_data['table_id'] = obj.id
        self.table_id = obj.id
        self.handle_response_data()
        self.response_callback()
        return generate_response(message='create success', data=self.response_data)

    @handle_api_error()
    def put(self):
        self.handle_request_params()
        obj = db.session.query(self.table_orm).filter(self.table_orm.id == self.table_id).first()
        form_data = dict()
        for key, value in self.form_data.items():
            if hasattr(self.table_orm, key):
                form_data.setdefault(key, value)
        info = self.table_schema().load(form_data)
        if not obj:
            raise ValueError(f'use table_id:{self.table_id} can not find')
        with db.auto_commit():
            db.session.query(self.table_orm).filter(self.table_orm.id == self.table_id).update(info)
        self.response_data['table_id'] = obj.id
        self.handle_response_data()
        self.response_callback()
        return generate_response(message='update success', data=self.response_data)

    @handle_api_error()
    def delete(self):
        self.handle_request_params()
        with db.auto_commit():
            if hasattr(self.table_orm, 'active'):
                db.session.query(self.table_orm).filter(self.table_orm.id == self.table_id).update({'active': 0})
            else:
                db.session.query(self.table_orm).filter(self.table_orm.id == self.table_id).delete()

        self.response_data['table_id'] = self.table_id
        self.response_callback()
        return generate_response(message='delete success', data=self.response_data)
